﻿/* 
 * Copyright (c) 2011-13 Andrey Bulygin
 * 
 * This file is part of Interceptor.
 * Interceptor is free software: you can redistribute it and/or modify it under the terms of the GNU 
 * Library General Public License as published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * Interceptor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Library General Public License for more details. You should have received a copy of the GNU 
 * Library General Public License along with Interceptor. If not, write to the Free Software Foundation, Inc., 59 
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Interceptor.Core.Exceptions;

namespace Interceptor.Core.Objects
{
	internal class ItcHolderDescriptor
	{
		private static readonly ItcHolderDescriptor _empty = new ItcHolderDescriptor(null,new ItcMethodDefinition[0], new AttrFilterDefinition[0]);
		public static ItcHolderDescriptor Empty { get { return _empty; }}

		public ItcMethodDefinition[] Interceptors { get; private set; }
		public AttrFilterDefinition[] AttributeFilters { get; private set; }
		public Type Definition { get; private set; }
		private ItcHolderDescriptor(Type interceptor, ItcMethodDefinition[] interceptors, AttrFilterDefinition[] attributeFilters)
		{
			Definition = interceptor;
			Interceptors = interceptors;
			AttributeFilters = attributeFilters;
		}

		public static ItcHolderDescriptor GetDescription(Type itcHolderType)
		{
			ValidateItcType(itcHolderType);
			MethodInfo[] interceptorsMethods = GetActionInterceptors(itcHolderType);
			ValidateInterceptors(interceptorsMethods);
			MethodInfo[] attributeFilters = GetAttributeFilters(itcHolderType);
			ValidateAttributeFilters(attributeFilters);

			ItcMethodDefinition[] interceptors = interceptorsMethods.Select(x => new ItcMethodDefinition(x)).ToArray();
			AttrFilterDefinition[] attrFilters = attributeFilters.Select(x => new AttrFilterDefinition(x)).ToArray();

			return new ItcHolderDescriptor(itcHolderType, interceptors, attrFilters);
		}
		private static MethodInfo[] GetActionInterceptors(Type itcType)
		{
			return itcType.GetMethods().Where(x => x.GetCustomAttributes(typeof(ActionInterceptorAttribute), true).Length == 1).ToArray();
		}
		private static MethodInfo[] GetAttributeFilters(Type type)
		{
			return type.GetMethods(BindingFlags.Static | BindingFlags.Public)
						.Where(m => m.GetCustomAttributes(typeof(AttributeFilterAttribute), true).Length == 1)
						.ToArray();
		}
		private static void ValidateItcType(Type type)
		{

		}
		private static void ValidateInterceptors(MethodInfo[] interceptors)
		{
			var errors = new List<ValidationError>();
			foreach (var method in interceptors)
			{
				errors.AddRange(InterceptorValidator.Validate(method));
			}
			if (errors.Count > 0)
				throw new InterceptorValidationException(String.Join(Environment.NewLine + Environment.NewLine,
					errors.Select(x => String.Format("Interceptor: {0}. Error: {1}", x.MethodDefinition, x.Description)).ToArray()));
		}
		private static void ValidateAttributeFilters(MethodInfo[] attributeFilters)
		{
			var errors = new List<ValidationError>();
			foreach (var method in attributeFilters)
			{
				errors.AddRange(AttributeFilterValidator.Validate(method));
			}
			if (errors.Count > 0)
				throw new AttributeFilterValidationException(String.Join(Environment.NewLine + Environment.NewLine,
					errors.Select(x => String.Format("Attribute Filter: {0}. Error: {1}", x.MethodDefinition, x.Description)).ToArray()));
		}
	}
}
